package cn.zn.modules.budget.cur.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.zn.framework.common.exception.RRException;
import cn.zn.framework.common.utils.PageUtils;
import cn.zn.framework.common.utils.Query;
import cn.zn.framework.common.vo.CodeNameVO;
import cn.zn.modules.budget.cur.dao.TBudgetInfoDetailDao;
import cn.zn.modules.budget.cur.entity.TBudgetInfo;
import cn.zn.modules.budget.cur.entity.TBudgetInfoDetailAttach;
import cn.zn.modules.budget.cur.entity.TBudgetInfoDetailEntity;
import cn.zn.modules.budget.cur.service.TBudgetInfoDetailAttachService;
import cn.zn.modules.budget.cur.service.TBudgetInfoDetailService;
import cn.zn.modules.budget.cur.service.TBudgetInfoService;
import cn.zn.modules.budget.vo.ProjectMaxCodeAndDicType;
import cn.zn.modules.budget.vo.ProjectVo;
import cn.zn.modules.budget.vo.TempBudgetImportVo;
import cn.zn.modules.zzsys.inter.SysDicInter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("tBudgetInfoDetailService")
@Slf4j
public class TBudgetInfoDetailServiceImpl extends ServiceImpl<TBudgetInfoDetailDao, TBudgetInfoDetailEntity> implements TBudgetInfoDetailService {

    @Autowired
    private TBudgetInfoService tBudgetInfoService;
    @Autowired
    private TBudgetInfoDetailAttachService tBudgetInfoDetailAttachService;
    @Autowired
    private SysDicInter sysDicInter;
    private final String PROJECT_TYPE_CODE = "ysxm";

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        TBudgetInfoDetailEntity tBudgetInfoDetailEntity = BeanUtil.mapToBean(params, TBudgetInfoDetailEntity.class, true);
        IPage<TBudgetInfoDetailEntity> page = new Query<TBudgetInfoDetailEntity>().getPage(params);
        List<TBudgetInfoDetailEntity> list = baseMapper.queryPage(tBudgetInfoDetailEntity, page);
        page.setRecords(list);
        return new PageUtils(page);
    }

    @Override
    public TBudgetInfoDetailEntity findDetail(String id) {
        TBudgetInfoDetailEntity tBudgetInfoDetailEntity = new TBudgetInfoDetailEntity();
        tBudgetInfoDetailEntity.setId(id);
        List<TBudgetInfoDetailEntity> list = baseMapper.queryPage(tBudgetInfoDetailEntity, null);
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public void importDetail(MultipartFile file) {
        // 从EXCEL中获取数据
        try {
            @Cleanup InputStream io = file.getInputStream();
            ExcelReader reader = ExcelUtil.getReader(io, 0, true);
            List<Map<String, Object>> list = reader.readAll();
            final String deptKey = "dept";
            final String projectKey = "project";
            final String totalKey = "total";
            String deptName = "";
            String projectName = "";
            List<TempBudgetImportVo> tempBudgetImportVos = Lists.newArrayList();
            // 查询所有部门及项目
            Map<String, String> deptMap = this.baseMapper.queryDepts(null).stream().collect(Collectors.toMap(CodeNameVO::getName, CodeNameVO::getCode, (v1, v2) -> v1));
            Map<String, String> projectMap = this.baseMapper.queryProjects(null).stream().collect(Collectors.toMap(CodeNameVO::getName, CodeNameVO::getCode, (v1, v2) -> v1));
            for (Map<String, Object> map : list) {
                if (!map.containsKey("dept") || !map.containsKey("project")) {
                    throw new RRException("传入的模板不正确");
                }
                if (map.get(deptKey) != null) {
                    if (StrUtil.equalsIgnoreCase(StrUtil.trim(map.get(deptKey).toString()), "部门名称")) {
                        // 跳过中文标题行
                        continue;
                    }
                    if (StrUtil.isNotBlank(StrUtil.trim(map.get(deptKey).toString()))) {
                        // 替换部门名称
                        deptName = StrUtil.trim(map.get(deptKey).toString());
                    }
                }
                if (StrUtil.isBlank(deptName)) {
                    // 跳过前面未设置部门的行
                    continue;
                }
                if (map.get(projectKey) == null || StrUtil.isBlank(StrUtil.trim(map.get(projectKey).toString()))) {
                    // 跳过未设置预算项目的行
                    continue;
                }
                projectName = StrUtil.trim(map.get(projectKey).toString());
                Map<String, Object> filterMap = MapUtil.filter(map, (Filter<Map.Entry<String, Object>>) stringObjectEntry -> {
                    if (stringObjectEntry.getValue() != null
                            && StrUtil.isNotBlank(stringObjectEntry.getValue().toString())
                            && !StrUtil.equalsIgnoreCase(stringObjectEntry.getKey(), totalKey)
                            && !StrUtil.equalsIgnoreCase(stringObjectEntry.getKey(), deptKey)
                            && !StrUtil.equalsIgnoreCase(stringObjectEntry.getKey(), projectKey)) {
                        return true;
                    }
                    return false;
                });
                if (filterMap.isEmpty()) {
                    // 跳过没有设置数值的行
                    continue;
                }
                tempBudgetImportVos.add(TempBudgetImportVo.builder()
                        .deptCode(deptMap.containsKey(deptName) ? deptMap.get(deptName) : null)
                        .deptName(deptName)
                        .projectCode(projectMap.containsKey(projectName) ? projectMap.get(projectName) : null)
                        .projectName(projectName)
                        .content(JSONUtil.parseFromMap(filterMap).toString())
                        .build());
            }
            if (tempBudgetImportVos.isEmpty()) {
                throw new RRException("没有需要导入的数据");
            }
            this.baseMapper.dropTempBudgetImport();
            this.baseMapper.createTempBudgetImport();
            this.baseMapper.clearTempBudgetImport();
            int insertCount = this.baseMapper.insertTempBudgetImport(tempBudgetImportVos);
            log.debug("insertCount:{}", insertCount);
        } catch (IOException e) {
            throw new RRException("读取文件内容时出错");
        }
    }

    @Override
    public List<String> queryNoDept() {
        return this.baseMapper.queryNoDept();
    }

    @Override
    public List<String> queryNoProject() {
        return this.baseMapper.queryNoProject();
    }

    @Override
    public void saveDept(String deptOld, String dept) {
        List<CodeNameVO> codeNameVos = this.baseMapper.queryDepts(dept);
        if (codeNameVos.size() == 0) {
            throw new RRException("部门不存在");
        }
        this.baseMapper.updateTempBudgetImportDept(codeNameVos.get(0).getCode(), codeNameVos.get(0).getName(), deptOld);
    }

    @Override
    public void saveProjectAll() {
        List<String> projects = this.queryNoProject();
        List<CodeNameVO> codeNameVos = sysDicInter.saveSysDicDatas(PROJECT_TYPE_CODE, projects);
        codeNameVos.forEach(o -> {
            this.baseMapper.updateTempBudgetImportProjectCode(o.getCode(), o.getName());
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAll(String remark) {
        List<TempBudgetImportVo> tempBudgetImportVos = this.baseMapper.selectTempBudgetImport();
        List<TBudgetInfoDetailEntity> list = Lists.newArrayList();
        for (int i = 0; i < tempBudgetImportVos.size(); i++) {
            JSONObject jsonObject = JSON.parseObject(tempBudgetImportVos.get(i).getContent());
            TempBudgetImportVo tempBudgetImportVo = tempBudgetImportVos.get(i);
            jsonObject.entrySet().forEach(o -> {
                TBudgetInfoDetailEntity tBudgetInfoDetailEntity = new TBudgetInfoDetailEntity();
                tBudgetInfoDetailEntity.setBudgetType(1);
                tBudgetInfoDetailEntity.setDeptCode(tempBudgetImportVo.getDeptCode());
                tBudgetInfoDetailEntity.setProjectCode(tempBudgetImportVo.getProjectCode());
                tBudgetInfoDetailEntity.setCateCode(o.getKey());
                tBudgetInfoDetailEntity.setMoney(NumberUtil.toBigDecimal(o.getValue().toString()).setScale(2).doubleValue());
                tBudgetInfoDetailEntity.setState(0);
                tBudgetInfoDetailEntity.setYear(LocalDate.now().getYear());
                tBudgetInfoDetailEntity.setRemark(remark);
                list.add(tBudgetInfoDetailEntity);
            });
        }
        super.saveBatch(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAudit(List<String> ids, Boolean result) {
        if (result) {
            List<TBudgetInfoDetailEntity> entities = super.list(new QueryWrapper<TBudgetInfoDetailEntity>().in("ID_", ids));
            // budgetType=1,直接激活
            List<TBudgetInfoDetailEntity> entitiesActive = CollUtil.newArrayList();
            // 需要人工激活
            List<TBudgetInfoDetailEntity> entitiesOther = CollUtil.newArrayList();
            entities.stream().forEach(o -> {
                if (o.getBudgetType() == 1) {
                    entitiesActive.add(o);
                } else {
                    entitiesOther.add(o);
                }
            });
            if (entitiesActive.size() > 0) {
                this.toActive(entitiesActive);
            }
            if (entitiesOther.size() > 0) {
                super.update(new UpdateWrapper<TBudgetInfoDetailEntity>().in("ID_", entitiesOther.stream().map(o -> o.getId()).collect(Collectors.toList()))
                        .set("STATE_", 1)
                );
            }
        } else {
            super.update(new UpdateWrapper<TBudgetInfoDetailEntity>().in("ID_", ids)
                    .set("STATE_", 3)
            );
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveActive(List<String> ids) {
        List<TBudgetInfoDetailEntity> entities = super.list(new QueryWrapper<TBudgetInfoDetailEntity>().in("ID_", ids));
        this.toActive(entities);
    }

    @Override
    public void deleteEntity(List<String> ids) {
        List<TBudgetInfoDetailEntity> list = super.list(new QueryWrapper<TBudgetInfoDetailEntity>().in("ID_", ids)
                .gt("STATE_", 0));
        if (list.size() > 0) {
            throw new RRException("预算已审核，不能删除");
        }
        // 删除附件
        tBudgetInfoDetailAttachService.remove(new QueryWrapper<TBudgetInfoDetailAttach>().in("T_BUDGET_INFO_DETAIL_ID_", ids));
        super.removeByIds(ids);
    }

    private void toActive(List<TBudgetInfoDetailEntity> details) {
        details.stream().forEach(o -> {
            super.update(new UpdateWrapper<TBudgetInfoDetailEntity>().eq("ID_", o.getId())
                    .set("STATE_", 2)
            );
            TBudgetInfo tBudgetInfo = tBudgetInfoService.getOne(new QueryWrapper<TBudgetInfo>()
                    .eq("YEAR_", o.getYear())
                    .eq("DEPT_CODE_", o.getDeptCode())
                    .eq("PROJECT_CODE_", o.getProjectCode())
                    .eq("CATE_CODE_", o.getCateCode())
                    .ge("TOTAL_MONEY_", 0)
            );
            if (tBudgetInfo == null) {
                tBudgetInfo = new TBudgetInfo();
                BeanUtil.copyProperties(o, tBudgetInfo);
                tBudgetInfo.setId(null);
                tBudgetInfo.setTotalMoney(o.getMoney());
                tBudgetInfoService.save(tBudgetInfo);
            } else {
                tBudgetInfoService.update(new UpdateWrapper<TBudgetInfo>().eq("ID_", tBudgetInfo.getId())
                        .set("TOTAL_MONEY_", NumberUtil.add(o.getMoney(), tBudgetInfo.getTotalMoney()))
                );
            }
        });
    }

}
